#include "FileSystem.h"

#include <Windows.h>

std::wstring appPath;
std::wstring currentPath; // FIXME: this can change dynamically

std::wstring getAppPath() {
	if (appPath.empty()) {
		std::vector<wchar_t> buf(4096);
		int len = GetModuleFileNameW(NULL, buf.data(), buf.size() - 1);
		buf[len] = 0;
		appPath = std::wstring(buf.data());
		len = appPath.find_last_of(L"\\/");
		if (len > 0) appPath = appPath.substr(0, len + 1);
	}
	return appPath;
}

std::wstring getCurrentPath() {
	if (currentPath.empty()) {
		int len = GetCurrentDirectoryW(0, NULL);
		if (len > 0) {
			std::vector<wchar_t> buf(len);
			GetCurrentDirectoryW(len, buf.data());
			currentPath = buf.data();
			len = currentPath.find_last_of(L"\\/");
			if (len != currentPath.size() - 1) currentPath += L"\\";
		}
	}
	return currentPath;
}

std::wstring getFullPath(const std::wstring& path) {
	std::vector<wchar_t> buf(1);
	int len = GetFullPathNameW(path.c_str(), 1, buf.data(), NULL);
	if (len > 0) {
		buf.resize(len);
		GetFullPathNameW(path.c_str(), len, buf.data(), NULL);
		return std::wstring(buf.data());
	}
	return std::wstring();
}

const char* myfgets(FILE* file, std::string& s) {
	s.clear();

	if (file) {
		char c;
		for (int i = 0;; i++){
			if (fread(&c, 1, 1, file) == 0) return (i > 0) ? s.c_str() : NULL;
			s.push_back(c);
			if (c == '\n') return s.c_str();
		}
	}

	return NULL;
}

FindFiles::FindFiles(const std::wstring& path_)
	: path(path_)
{
	for (int i = 0, m = path.size(); i < m; i++) {
		if (path[i] == L'/') path[i] = L'\\';
	}
	if (!path.empty() && path.back() != L'\\') path.push_back(L'\\');

	std::wstring tmpPath = path + L'*';

	WIN32_FIND_DATAW fd;
	HANDLE h = FindFirstFileW(tmpPath.c_str(), &fd);
	
	if (h != INVALID_HANDLE_VALUE) {
		do {
			FileData f;
			f.fileName = fd.cFileName;
			if (f.fileName != L"." && f.fileName != L"..") {
				f.creationTime = (unsigned long long)fd.ftCreationTime.dwLowDateTime | (((unsigned long long)fd.ftCreationTime.dwHighDateTime) << 32);
				f.lastAccessTime = (unsigned long long)fd.ftLastAccessTime.dwLowDateTime | (((unsigned long long)fd.ftLastAccessTime.dwHighDateTime) << 32);
				f.lastWriteTime = (unsigned long long)fd.ftLastWriteTime.dwLowDateTime | (((unsigned long long)fd.ftLastWriteTime.dwHighDateTime) << 32);
				f.fileSize = (unsigned long long)fd.nFileSizeLow | (((unsigned long long)fd.nFileSizeHigh) << 32);
				if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
					f.fileName.push_back(L'\\');
					directories.push_back(f);
				} else {
					files.push_back(f);
				}
			}
		} while (FindNextFileW(h, &fd));
		FindClose(h);
	}
}

FindFilesRecursive::FindFilesRecursive(const std::wstring& path_)
	: FindFiles(path_)
{
	for (const auto& f : directories) {
		dirs.emplace_back(new FindFilesRecursive(path + f.fileName));
	}
}
